package com.thales.sentinel.service;

import Aladdin.Hasp;
import Aladdin.HaspStatus;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.thales.sentinel.model.LicenseException;
import com.thales.sentinel.model.LicenseInfo;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Value;

/**
 * 许可证验证服务
 * 负责从加密狗读取许可证信息并进行各种验证
 */
@Service
public class LicenseValidationService {
    
    // 供应商代码 - 与LdkLicensingService中保持一致
    private static final String VENDOR_CODE = new String(
            "AzIceaqfA1hX5wS+M8cGnYh5ceevUnOZIzJBbXFD6dgf3tBkb9cvUF/Tkd/iKu2fsg9wAysYKw7RMA" +
                    "sVvIp4KcXle/v1RaXrLVnNBJ2H2DmrbUMOZbQUFXe698qmJsqNpLXRA367xpZ54i8kC5DTXwDhfxWT" +
                    "OZrBrh5sRKHcoVLumztIQjgWh37AzmSd1bLOfUGI0xjAL9zJWO3fRaeB0NS2KlmoKaVT5Y04zZEc06" +
                    "waU2r6AU2Dc4uipJqJmObqKM+tfNKAS0rZr5IudRiC7pUwnmtaHRe5fgSI8M7yvypvm+13Wm4Gwd4V" +
                    "nYiZvSxf8ImN3ZOG9wEzfyMIlH2+rKPUVHI+igsqla0Wd9m7ZUR9vFotj1uYV0OzG7hX0+huN2E/Id" +
                    "gLDjbiapj1e2fKHrMmGFaIvI6xzzJIQJF9GiRZ7+0jNFLKSyzX/K3JAyFrIPObfwM+y+zAgE1sWcZ1" +
                    "YnuBhICyRHBhaJDKIZL8MywrEfB2yF+R3k9wFG1oN48gSLyfrfEKuB/qgNp+BeTruWUk0AwRE9XVMU" +
                    "uRbjpxa4YA67SKunFEgFGgUfHBeHJTivvUl0u4Dki1UKAT973P+nXy2O0u239If/kRpNUVhMg8kpk7" +
                    "s8i6Arp7l/705/bLCx4kN5hHHSXIqkiG9tHdeNV8VYo5+72hgaCx3/uVoVLmtvxbOIvo120uTJbuLV" +
                    "TvT8KtsOlb3DxwUrwLzaEMoAQAFk6Q9bNipHxfkRQER4kR7IYTMzSoW5mxh3H9O8Ge5BqVeYMEW36q" +
                    "9wnOYfxOLNw6yQMf8f9sJN4KhZty02xm707S7VEfJJ1KNq7b5pP/3RjE0IKtB2gE6vAPRvRLzEohu0" +
                    "m7q1aUp8wAvSiqjZy7FLaTtLEApXYvLvz6PEJdj4TegCZugj7c8bIOEqLXmloZ6EgVnjQ7/ttys7VF" +
                    "ITB3mazzFiyQuKf4J6+b/a/Y");
    
    private static final int DEMO_MEMBUFFER_SIZE = 2048;
    
    private final ObjectMapper objectMapper;
    private LicenseInfo cachedLicenseInfo;
    private LocalDateTime lastCacheTime;
    private static final long CACHE_DURATION_MINUTES = 5; // 缓存5分钟
    @Value("${ldk.license.feature-id:0}")
    private int featureId;

    public LicenseValidationService() {
        this.objectMapper = new ObjectMapper();
        this.objectMapper.registerModule(new JavaTimeModule());
    }
    
    /**
     * 应用启动时验证许可证
     */
    @PostConstruct
    public void validateLicenseOnStartup() {
        try {
            LicenseInfo licenseInfo = readLicenseFromHasp();
            validateLicenseExpiration(licenseInfo);
            System.out.println("许可证验证通过，应用启动成功");
            System.out.println("许可证过期时间: " + licenseInfo.getExpirationDate());
            System.out.println("最大用户数: " + licenseInfo.getMaxUsers());
        } catch (LicenseException e) {
            System.err.println("许可证验证失败: " + e.getMessage());
            System.err.println("应用启动失败，请检查许可证");
            // 在生产环境中，这里应该终止应用启动
            // System.exit(1);
            throw e;
        }
    }
    
    /**
     * 从加密狗读取许可证信息
     * @return 许可证信息对象
     * @throws LicenseException 读取失败时抛出异常
     */
    public LicenseInfo readLicenseFromHasp() throws LicenseException {
        // 检查缓存
        if (cachedLicenseInfo != null && lastCacheTime != null && 
            lastCacheTime.plusMinutes(CACHE_DURATION_MINUTES).isAfter(LocalDateTime.now())) {
            return cachedLicenseInfo;
        }
        
        Hasp hasp = new Hasp(featureId); // 使用功能ID
        
        try {
            // 登录到密钥
            hasp.login(VENDOR_CODE);
            int status = hasp.getLastError();
            
            if (status != HaspStatus.HASP_STATUS_OK) {
                throw new LicenseException(
                    getLicenseErrorType(status),
                    "加密狗登录失败，错误码: " + status + " (" + getStatusDescription(status) + ")"
                );
            }
            
            // 获取只读内存大小
            int fileSize = hasp.getSize(Hasp.HASP_FILEID_RO);
            status = hasp.getLastError();
            
            if (status != HaspStatus.HASP_STATUS_OK) {
                throw new LicenseException(
                    LicenseException.LicenseErrorType.LICENSE_READ_ERROR,
                    "获取只读内存大小失败，错误码: " + status
                );
            }
            
            // 限制读取大小
            if (fileSize > DEMO_MEMBUFFER_SIZE) {
                fileSize = DEMO_MEMBUFFER_SIZE;
            }
            
            // 读取内存内容
            byte[] memBuffer = new byte[DEMO_MEMBUFFER_SIZE];
            hasp.read(Hasp.HASP_FILEID_RO, 0, memBuffer);
            status = hasp.getLastError();
            
            if (status != HaspStatus.HASP_STATUS_OK) {
                throw new LicenseException(
                    LicenseException.LicenseErrorType.LICENSE_READ_ERROR,
                    "读取只读内存失败，错误码: " + status
                );
            }
            
            // 找到第一个null字符的位置
            int endIndex = memBuffer.length;
            for (int i = 0; i < memBuffer.length; i++) {
                if (memBuffer[i] == 0) {
                    endIndex = i;
                    break;
                }
            }
            
            String jsonContent = new String(memBuffer, 0, endIndex).trim();
            
            // 解析JSON
            try {
                LicenseInfo licenseInfo = objectMapper.readValue(jsonContent, LicenseInfo.class);
                
                // 更新缓存
                cachedLicenseInfo = licenseInfo;
                lastCacheTime = LocalDateTime.now();
                
                return licenseInfo;
            } catch (Exception e) {
                throw new LicenseException(
                    LicenseException.LicenseErrorType.LICENSE_PARSE_ERROR,
                    "解析许可证JSON失败: " + e.getMessage(),
                    e
                );
            }
            
        } finally {
            // 确保登出
            hasp.logout();
        }
    }
    
    /**
     * 验证许可证是否过期
     * @param licenseInfo 许可证信息
     * @throws LicenseException 如果许可证已过期
     */
    public void validateLicenseExpiration(LicenseInfo licenseInfo) throws LicenseException {
        if (licenseInfo.isExpired()) {
            throw new LicenseException(
                LicenseException.LicenseErrorType.LICENSE_EXPIRED,
                "许可证已于 " + licenseInfo.getExpirationDate() + " 过期"
            );
        }
    }
    
    /**
     * 验证用户数量是否超过限制
     * @param currentUserCount 当前用户数量
     * @throws LicenseException 如果用户数量超过限制
     */
    public void validateUserCount(int currentUserCount) throws LicenseException {
        LicenseInfo licenseInfo = readLicenseFromHasp();
        validateLicenseExpiration(licenseInfo); // 同时检查过期
        
        int maxUsers = licenseInfo.getMaxUsers();
        if (maxUsers > 0 && currentUserCount >= maxUsers) {
            throw new LicenseException(
                LicenseException.LicenseErrorType.MAX_USERS_EXCEEDED,
                "用户数量已达到许可证限制 (" + maxUsers + ")，无法创建更多用户"
            );
        }
    }
    
    /**
     * 验证功能是否被许可
     * @param feature 功能名称
     * @throws LicenseException 如果功能未被许可
     */
    public void validateFeature(String feature) throws LicenseException {
        LicenseInfo licenseInfo = readLicenseFromHasp();
        validateLicenseExpiration(licenseInfo); // 同时检查过期
        
        if (!licenseInfo.isFeatureEnabled(feature)) {
            throw new LicenseException(
                LicenseException.LicenseErrorType.FEATURE_NOT_LICENSED,
                "功能 '" + feature + "' 未被许可"
            );
        }
    }
    
    /**
     * 获取当前许可证信息（用于显示）
     * @return 许可证信息
     */
    public LicenseInfo getCurrentLicenseInfo() {
        return readLicenseFromHasp();
    }
    
    /**
     * 清除许可证缓存
     */
    public void clearCache() {
        cachedLicenseInfo = null;
        lastCacheTime = null;
    }
    
    /**
     * 根据HASP状态码获取对应的许可证错误类型
     */
    private LicenseException.LicenseErrorType getLicenseErrorType(int status) {
        switch (status) {
            case HaspStatus.HASP_FEATURE_NOT_FOUND:
            case HaspStatus.HASP_HASP_NOT_FOUND:
            case HaspStatus.HASP_NO_DRIVER:
                return LicenseException.LicenseErrorType.HASP_NOT_FOUND;
            default:
                return LicenseException.LicenseErrorType.HASP_LOGIN_FAILED;
        }
    }
    
    /**
     * 获取状态码描述
     */
    private String getStatusDescription(int status) {
        switch (status) {
            case HaspStatus.HASP_FEATURE_NOT_FOUND:
                return "未找到指定功能";
            case HaspStatus.HASP_HASP_NOT_FOUND:
                return "未找到Sentinel密钥";
            case HaspStatus.HASP_OLD_DRIVER:
                return "驱动版本过旧";
            case HaspStatus.HASP_NO_DRIVER:
                return "未安装驱动";
            case HaspStatus.HASP_INV_VCODE:
                return "无效的供应商代码";
            default:
                return "未知错误";
        }
    }
}